feat(telemetry): enable session tracking and flush envelopes on exit#71
Merged
lukeocodes merged 1 commit intomainfrom May 8, 2026
Merged
feat(telemetry): enable session tracking and flush envelopes on exit#71lukeocodes merged 1 commit intomainfrom
lukeocodes merged 1 commit intomainfrom
Conversation
Two small additions to deepctl-telemetry so the dx-cli Sentry project gets release-health signal alongside errors: 1. `auto_session_tracking=True` in sentry_sdk.init. Already the SDK default, but spelling it out makes the contract explicit and defends against a future SDK release flipping the default off. 2. New `_flush_on_exit` registered via `atexit.register` after a successful init. Calls `sentry_sdk.flush(timeout=2.0)` so the session envelope (and any error envelope captured at the very tail of execution) actually leaves the process before Python tears down. Without this, short-lived `dg` invocations can lose their session record entirely. Wrapped in a bare except so a Sentry hang or network glitch can never block CLI exit. 2s is the maximum the user waits. After this lands, the Releases view in Sentry (https://deepgram.sentry.io/releases/?project=4510993603362816) starts showing per-version session counts and crash-free percentages — the 'is anyone actually using v0.2.X' dashboard. Errors-only contract is preserved: traces_sample_rate stays 0, profiles_sample_rate stays 0, no per-command instrumentation. Tests: 5 new cases in TestSessionFlush covering auto_session_tracking being set to True in init kwargs, atexit registration of _flush_on_exit, no atexit registration when telemetry is disabled, 2.0s flush timeout, and exception suppression in the flush path.
lukeocodes
added a commit
that referenced
this pull request
May 9, 2026
## The bug [#71](#71) enabled `auto_session_tracking=True` expecting sentry-sdk to start sessions automatically. It doesn't — in sentry-sdk 2.x, that flag only tells **integrations** (Flask, Django, ASGI request handlers) to wrap each request in a session. CLIs have no integration that knows when an 'application session' begins, so no session is ever created. Confirmed via `SENTRY_DEBUG=1`: the worker flushed but no `Sending envelope` line ever appeared, and the [Releases dashboard](https://deepgram.sentry.io/releases/?project=4510993603362816) showed zero `deepctl@*` releases despite #71 having shipped. ## The fix One line — call `sentry_sdk.start_session()` right after init. Default `session_mode` is already `"application"` per [scope.py L1558](https://github.com/getsentry/sentry-python/blob/2.59.0/sentry_sdk/scope.py#L1558). The atexit handler from #71 then catches the session in its flush. ```python sentry_sdk.init(...) # unchanged sentry_sdk.set_tag(...) # unchanged sentry_sdk.start_session() # NEW atexit.register(_flush_on_exit) # unchanged ``` ## Proof Pre-fix `SENTRY_DEBUG=1` (worker flushes empty queue): ``` [sentry] DEBUG: Flushing HTTP transport [sentry] DEBUG: background worker got flush request [sentry] DEBUG: background worker flushed [sentry] DEBUG: atexit: got shutdown signal [sentry] DEBUG: Killing HTTP transport ``` Post-fix: ``` [sentry] DEBUG: atexit: got shutdown signal [sentry] DEBUG: Flushing HTTP transport [sentry] DEBUG: Sending envelope [envelope with 1 items (session)] project:4510993603362816 host:o206115.ingest.us.sentry.io ``` The session envelope ships to the `dx-cli` project (id `4510993603362816`). ## Bonus catch — the silent failure that masked this While diagnosing, my first attempt was `session_mode="application"` as an init kwarg. sentry-sdk 2.59.0 raises `TypeError: Unknown option 'session_mode'` for that, which the `try/except: pass` wrapper in `src/deepctl/main.py` silently swallowed. The CLI ran fine; telemetry was just dead. Added a regression test (`assert 'session_mode' not in kwargs`) so a future kwargs change can't reintroduce that failure. ## Tests ``` 11 passed in 0.04s ``` New: `test_init_starts_session` asserts `sentry_sdk.start_session()` is called once after init. Updated `test_init_enables_auto_session_tracking` with the `session_mode` regression guard.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Today the `dx-cli` Sentry project has zero events. That's expected for an errors-only telemetry contract on a CLI that's been live <24h — most users haven't hit an unhandled exception. But it also means there's no signal at all: we can't tell "is anyone running v0.2.22?" from the dashboard.
Sessions fix that without violating the errors-only design.
What changed
Two lines in `packages/deepctl-telemetry/src/deepctl_telemetry/client.py`:
```python
sentry_sdk.init(
...
auto_session_tracking=True, # NEW (already the SDK default; explicit now)
traces_sample_rate=0.0, # unchanged
profiles_sample_rate=0.0, # unchanged
...
)
atexit.register(_flush_on_exit) # NEW
```
Plus a tiny module-level helper:
```python
def _flush_on_exit() -> None:
try:
import sentry_sdk
sentry_sdk.flush(timeout=2.0)
except Exception:
pass
```
What it gives us
After the next release lands on PyPI and a few users invoke `dg`:
What it doesn't change
Why `atexit` and not `Sentry.flush()` inline somewhere
CLI commands have multiple exit paths — `return BaseResult(...)`, raised exceptions, `ctx.exit()` from Click, sys.exit on signal, etc. `atexit` is the only hook that fires on all of them. The 2-second budget caps user-visible exit delay even if Sentry is unreachable. The bare-`except` ensures a Sentry hang can never block process termination.
Test plan
5 new cases in `TestSessionFlush`:
Full suite: `uv run pytest packages/deepctl-telemetry/tests/` → 10 passed in 0.06s.